import java.util.Scanner;

//形参与实参的关系
public class Test {
    //计算1!+2!+3!+4!+5!
    public static int func1(int x) {
        int ret = 1;
        for (int j = 1; j <= x; j++) {
            ret *= j;
        }
        return ret;
    }

    public static int funcSum1(int n) {
        //这部分也创造了一个栈帧
        int sum = 0;
        for (int i = 1; i <= n; i++) {
            sum += func1(i);
        }
        return sum;
    }
    //这部分我用方法实现的

    public static void main1(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int n = 5;
//        for (int i = 1; i <= a; i++) {
//            sum += func(i);
//        }
        //这部分我也可以用方法来实现
        //System.out.println(funcSum(5));//这部分显示的有个n，这是编译器自己加的
//        System.out.println(funcSum(n));
        //这是main方法的n，它与funcSum中不相同
        //因为它创造了一个栈帧
        sc.close();
    }
    //上面的，这就表明了形参只是拿到了实参的值
    //但是两者的栈帧并不一样，都是在一个栈空间中，但是所处的区域不同

    public static int add1(int a, int b){
        return a + b;
    }

    //add(2, 3);
    // 2和3是实参，在调用时传给形参a和b

    //在Java中，实参的值永远都是赋值给形参，形参和实参本质是两个实体（东西）

    //老生常谈的例子：
    //交换变量
    //正常版：
    public static void main2(String[] args){
        int a = 10;
        int b = 20;
        int temp = 0;
        temp = a;
        a = b;
        b =temp;
        System.out.println(a + " " + b);
    }
    //方法版
    public static void swap4(int x ,int y) {
        int temp = 0;
        temp = x;
        x = y;
        y =temp;

    }
    //当这个方法走完，那么也就是把x和y的变量的值进行交换完成。
    //但是也只是把它们被赋予的值进行交换完成
    //对于a和b的本身没有任何影响
    public static void main3(String[] args){
        int a = 10;
        int b = 20;
        //a和b的局部变量
        //作用域：在方法中
        //生命周期：调用方法的创建，方法调用结束的时候来销毁
        //内存：储存在栈上
        //Java中由于其安全性，不会让你拿到局部变量的地址
        System.out.println("交换前"+ a + " " + b);
        //swap(a,b);
        System.out.println("交换后"+ a + " " + b);
    }
//    就目前来看，学完类和对象才能知道怎么交换
//    Java中没有指针这一个概念
//    但是有引用这一个概念，“引用”叫做引用变量
//    引用变量中存入的是地址
//    数组就是一个引用变量

    //当一个方法没有返回值，所以我们就要用void类型来接收

    //方法重载
    //指的是一个词语有多个意思我们就称作为方法重载

//    public static int addInt(int x,int y){
//        return x + y;
//    }
//
//    public static double addDouble (double x,double y){
//        return x + y;
//    }

    //这时候方法里的名字不一样，所以我们可以创建新的方法名从而计算。
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int a = sc.nextInt();
        int b = sc.nextInt();
//        System.out.println(addInt(a, b));
        //System.out.println(add(a, b));
        double c1 = sc.nextDouble();
        double c2 = sc.nextDouble();
//        System.out.println(addDouble(c1,c2));
        //System.out.println(add(c1,c2));
        sc.close();
    }

    public static int add2(int x,int y){
        return x + y;
    }
    public static double add3(double x,double y){
        return (int)(x + y);
        //这么做强制转化，但是仅仅是返回值不同，这种仅有返回值改变，那么这就不叫做方法重载
    }
    //这部分方法叫做重载，只有一个名字都是add

    //方法重载：
    //1.方法名相同
    //2.参数列表不同【数据类型，变量个数，顺序】
    //返回值不影响重载

    //在Java中如果多个方法的名字相同，参数列表不同，则称该几种方法被重载了。
    //如果仅仅返回值不同，那么不会构成重载

    //Javap -v和Javap -c这两个命令有什么区别

    //递归
//    必要条件：
//    1.将原问题转为多个子问题，（子问题必须要与原问题解法相同）
//    2.递归出口

    //阶乘
    public static int func(int n){
        if(n == 1 || n == 0){
            return 1;
        }
        int ret = n * func(n-1);
        return ret;
    }
    public static void main5(String[] args) {
        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        System.out.println(func(5));
    }

    //调用栈：
    //方法调用的时候，会有一个“栈”这样的内存空间描述当前的调用关系，称为调用栈.
    //每一次的方法调用就称为一个 "栈帧", 每个栈帧中包含了这次调用的参数是哪些, 返回到哪里继续执行等信息.
    //后面我们借助 IDEA 很容易看到调用栈的内容

    //我们可以用调试来看递归的过程 Debug

    //练习：
    //按顺序打印一个数字的每一位(例如 1234 打印出 1 2 3 4)
    public static void print (int n){
        if(n > 9){
            print(n / 10);
        }
        //当n为一个数时，那么可以直接打印
        System.out.print(n % 10 + " ");
    }

    public static void main6(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        print(n);
    }



    //递归求 1 + 2 + 3 + ... + 10
    public static int sum (int num){
        if(num == 1){
            return 1;
        }
        int ret = num + sum(num - 1);
        return ret;
    }

    public static void main7(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        System.out.println(sum(n));
    }

    //求斐波那契数列的第 N 项
    //递归算法
    public static int funca(int n) {
        /*if(n <= 2)*/if(n == 1 || n == 2){
            return 1;
            //这两种写法均可以
        }else {
            return  funca(n - 1) + funca(n - 2);
        }
    }

    public static void main8(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        System.out.println(funca(n));
    }
    //这个代码不适合用递归去写，程序执行速度极慢. 原因是进行了大量的重复运算.

    //迭代写法
    public static long funcaA(long n){
        long a = 1;
        long b = 1;
        long c = 1;
        while(n > 2){
            c = a + b;
            a = b;
            b = c;
            n--;
        }
        return c;
    }
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        long n = sc.nextInt();
        System.out.println(funcaA(n));
    }
    //在二叉树我们经常需要使用递归去解决问题
}
